
import Foundation
import UIKit
import SnapKit
import WebKit
import EachNavigationBar
import Toast

fileprivate struct TuBiaoZheXianYuanZhu_Status {
    static let progress = "estimatedProgress"
    static let title = "title"
    static let getAppBundleId = "getAppBundleId"
    static let getAppVersion = "getAppVersion"
    static let openUrl = "openUrl"
    static let removeAllCached = "removeAllCached"
    static let removeAllCookie = "removeAllCookie"
    static let savePicture = "savePicture"
    static let setApplicaitonBadgeValue = "setApplicaitonBadgeValue"
    static let getPhoneModel = "getPhoneModel"
    static let getPhoneOs = "getPhoneOs"
    static let registerPush = "registerPush"
    static let unRegisterPush = "unRegisterPush"
    static let loginSuccessInH5 = "loginSuccessInH5"
}

@objcMembers
class TuBiaoZheXianYuanZhu_BadgeVC: UIViewController {
    
    deinit {
        webView.removeObserver(self, forKeyPath: TuBiaoZheXianYuanZhu_Status.progress)
        webView.removeObserver(self, forKeyPath: TuBiaoZheXianYuanZhu_Status.title)
    }
    
    var urlString: String? {
        didSet {
            guard let urlStr = urlString else { return }
            guard let url = URL(string: urlStr) else { return }
            var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 20.0)
            if #available(iOS 13.0, *) {
                request.allowsExpensiveNetworkAccess = true
                request.allowsConstrainedNetworkAccess = true
            }
            if self.webView.isLoading {
                self.webView.stopLoading()
            }
            self.webView.load(request)
        }
    }
    
    var needNav: Bool = true
    
    var h5Title: String? {
        didSet {
            navigation.item.title = h5Title
        }
    }
    
    var htmlString: String? {
        didSet {
            guard let str = htmlString else { return }
            self.webView.loadHTMLString(str, baseURL: nil)
        }
    }
    
    var loadWebSuccess: Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        gs_addNetNotification()
        
        view.backgroundColor = .white
        navigation.bar.alpha = 0
        if navigation.item.leftBarButtonItem == nil {
            let bridgingItem = UIBarButtonItem(title: "关闭", style: .done, target: self, action: #selector(leftItemAction))
            navigation.item.leftBarButtonItem = bridgingItem
        }
        
        view.addSubview(webView)
        view.addSubview(progressView)
        view.addSubview(indicatorView)
        view.addSubview(progressLabel)
        
        webView.snp.makeConstraints { (make) in
            if (needNav) {
                make.top.equalTo(getNavTotalHeight())
            }else {
                make.top.equalToSuperview()
            }
            make.left.right.bottom.equalToSuperview()
        }
        progressView.snp.makeConstraints { (make) in
            if (needNav) {
                make.top.equalTo(getNavTotalHeight())
            }else {
                make.top.equalToSuperview()
            }
            make.left.right.equalToSuperview()
            make.height.equalTo(2)
        }
        indicatorView.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }
        progressLabel.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.top.equalTo(indicatorView.snp.bottom).offset(12)
        }
        
        webView.addObserver(self, forKeyPath: TuBiaoZheXianYuanZhu_Status.progress, options: NSKeyValueObservingOptions.new, context: nil)
        webView.addObserver(self, forKeyPath: TuBiaoZheXianYuanZhu_Status.title, options: NSKeyValueObservingOptions.new, context: nil)
    }
    
    /**
     添加网络监控
     */
    private func  gs_addNetNotification() {
        NetTokk.shared.onChange(by: { [weak self] mmm in
            guard let self = self else { return }
            switch mmm {
            case .cellular, .wifi: // 有网
                if !self.loadWebSuccess {
                    guard let str = urlString else { return }
                    self.urlString = str
                }
            default: // 无网
                if self.webView.isLoading {
                    self.webView.stopLoading()
                }
                self.progressLabel.text = "暂无网络连接，请检查网络连接\n如长时间无响应，请重启APP"
            }
        }, nonono: true)
    }
    
    @objc private func leftItemAction() {
        dismiss(animated: true, completion: nil)
    }
    
    lazy var webView: WKWebView = {
        let configuration = WKWebViewConfiguration()
        let userContentController = WKUserContentController()
        
        if #available(iOS 14.0, *) {
            let webpagePreferences = WKWebpagePreferences()
            webpagePreferences.allowsContentJavaScript = true
            configuration.defaultWebpagePreferences = webpagePreferences
        } else {
            configuration.preferences.javaScriptEnabled = true
        }
        
        configuration.allowsInlineMediaPlayback = true
        configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
        configuration.suppressesIncrementalRendering = true
        configuration.allowsAirPlayForMediaPlayback = true
        configuration.allowsInlineMediaPlayback = true
        configuration.allowsPictureInPictureMediaPlayback = true
        
        let jsNames = jsWithMethods()
        for name in jsNames {
            userContentController.add(self, name: name)
        }
        configuration.userContentController = userContentController

        let webView = WKWebView(frame: .zero, configuration: configuration)
        if #available(iOS 11.0, *) {
            webView.scrollView.contentInsetAdjustmentBehavior = .never
        }
        webView.navigationDelegate = self
        webView.isExclusiveTouch = false
        webView.uiDelegate = self
        webView.scrollView.decelerationRate = .normal
        webView.scrollView.bouncesZoom = false
        webView.allowsBackForwardNavigationGestures = true
        webView.scrollView.bounces = false
        webView.isHidden = true
        
        return webView
    }()
    
    private func jsWithMethods() -> [String] {
        return [TuBiaoZheXianYuanZhu_Status.getAppBundleId,
                TuBiaoZheXianYuanZhu_Status.getAppVersion,
                TuBiaoZheXianYuanZhu_Status.openUrl,
                TuBiaoZheXianYuanZhu_Status.removeAllCached,
                TuBiaoZheXianYuanZhu_Status.removeAllCookie,
                TuBiaoZheXianYuanZhu_Status.savePicture,
                TuBiaoZheXianYuanZhu_Status.setApplicaitonBadgeValue,
                TuBiaoZheXianYuanZhu_Status.getPhoneModel,
                TuBiaoZheXianYuanZhu_Status.getPhoneOs,
                TuBiaoZheXianYuanZhu_Status.registerPush,
                TuBiaoZheXianYuanZhu_Status.unRegisterPush,
                TuBiaoZheXianYuanZhu_Status.loginSuccessInH5]
    }
    
    private lazy var progressView: UIProgressView = {
        let progressView = UIProgressView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 2))
        progressView.tintColor = UIColor.init(red: 0.997, green: 0.942, blue: 0.329, alpha: 1)
        progressView.trackTintColor = .lightGray
        return progressView
    }()
    
    lazy var indicatorView: UIActivityIndicatorView = {
        let indicator: UIActivityIndicatorView
        if #available(iOS 13.0, *) {
            indicator = UIActivityIndicatorView(style: .medium)
        } else {
            indicator = UIActivityIndicatorView(style: .gray)
        }
        indicator.hidesWhenStopped = true
        indicator.isHidden = false
        return indicator
    }()
    
    lazy var progressLabel: UILabel = {
        let label = UILabel()
        label.textColor = .lightGray
        label.font = UIFont.systemFont(ofSize: 14)
        label.textAlignment = .center
        label.isHidden = false
        label.numberOfLines = 2
        return label
    }()
}

extension TuBiaoZheXianYuanZhu_BadgeVC: WKScriptMessageHandler {
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let jsName = message.name
        guard !jsName.isEmpty else {
            return
        }
        
        switch jsName {
        case TuBiaoZheXianYuanZhu_Status.getAppBundleId:
            let bundleIdentifier = Bundle.main.bundleIdentifier ?? ""
            sendJsMessage("\(jsName)('\(bundleIdentifier)')")
            
        case TuBiaoZheXianYuanZhu_Status.getAppVersion:
            let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
            sendJsMessage("\(jsName)('\(currentVersion)')")
            
        case TuBiaoZheXianYuanZhu_Status.openUrl:
            if let link = message.body as? String, let url = URL(string: link) {
                UIApplication.shared.open(url)
            }
            
        case TuBiaoZheXianYuanZhu_Status.removeAllCached:
            removeAllCached()
            
        case TuBiaoZheXianYuanZhu_Status.removeAllCookie:
            removeAllCookie()
            
        case TuBiaoZheXianYuanZhu_Status.savePicture:
            if let pictureString = message.body as? String, let img = stringToImage(pictureString) {
                UIImageWriteToSavedPhotosAlbum(img, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
            }
            
        case TuBiaoZheXianYuanZhu_Status.setApplicaitonBadgeValue:
            if let badgeNumber = message.body as? NSNumber {
                UIApplication.shared.applicationIconBadgeNumber = badgeNumber.intValue
            }
            
        case TuBiaoZheXianYuanZhu_Status.getPhoneModel:
            let deviceModel = UIDevice.getAppDeviceModel()
            sendJsMessage("\(jsName)('\(deviceModel)')")
            
        case TuBiaoZheXianYuanZhu_Status.getPhoneOs:
            let osVersion = UIDevice.getAppDeviceOsVersion()
            sendJsMessage("\(jsName)('\(osVersion)')")
            
        case TuBiaoZheXianYuanZhu_Status.registerPush:
            TimPushHelper.shared.registerPush()
            
        case TuBiaoZheXianYuanZhu_Status.unRegisterPush:
            TimPushHelper.shared.unRegisterPush()
            
        case TuBiaoZheXianYuanZhu_Status.loginSuccessInH5:
            if let token = message.body as? String {
                TimPushHelper.shared.loginSuccessInH5(token: token)
            }
        
        default:
            print("Received other messages: \(String(describing: message.body))")
        }
    }
    
    /// Sends JavaScript code to be executed in a WKWebView
    private func sendJsMessage(_ message: String) {
        print("Message to be sent soon = \(message)")
        webView.evaluateJavaScript(message) { response, error in
            if let error = error {
                print("Failed to send JS information: \(error)")
            } else {
                print("Successfully called JS method")
            }
        }
    }
    
    @objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
        if let error = error {
            print("Error saving image: \(error.localizedDescription)")
            self.view.makeToast("保存相册失败，请使用手机截屏", duration: 2, position: CSToastPositionCenter)
        } else {
            print("Image saved successfully")
            self.view.makeToast("保存相册成功", duration: 2, position: CSToastPositionCenter)
            // 发送消息
            sendJsMessage("savePictureSuccess()")
        }
    }
    
    // Clears all WKWebView caches
    private func removeAllCached() {
        let allWebsiteDataTypes = WKWebsiteDataStore.allWebsiteDataTypes()
        WKWebsiteDataStore.default().fetchDataRecords(ofTypes: allWebsiteDataTypes) { records in
            for record in records {
                WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {
                    print("Cache cleared successfully")
                    self.view.makeToast("清除缓存成功", duration: 2, position: CSToastPositionCenter)
                })
            }
        }
    }
    
    // Clears WKWebView cookie cache
    private func removeAllCookie() {
        let websiteDataTypes = Set([WKWebsiteDataTypeCookies])
        WKWebsiteDataStore.default().fetchDataRecords(ofTypes: websiteDataTypes) { records in
            for record in records {
                WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {
                    print("Cookies cleared successfully")
                    self.view.makeToast("清除Cookie成功", duration: 2, position: CSToastPositionCenter)
                })
            }
        }
    }
    
    private func stringToImage(_ str: String) -> UIImage? {
        var base64String = str
        
        // 检查并移除前缀
        if base64String.contains("data:image/png;base64,") {
            base64String = base64String.replacingOccurrences(of: "data:image/png;base64,", with: "")
        }
        if base64String.contains("data:image/jpeg;base64,") {
            base64String = base64String.replacingOccurrences(of: "data:image/jpeg;base64,", with: "")
        }
        
        // 将 Base64 字符串解码为 NSData
        guard let imageData = Data(base64Encoded: base64String, options: .init(rawValue: 0)) else {
            print("Unable to convert base64 string to NSData")
            return nil
        }
        
        // 使用 NSData 创建 UIImage
        if let photo = UIImage(data: imageData) {
            print("Image conversion successful")
            return photo
        } else {
            print("Unable to convert imageData to UIImage")
            return nil
        }
    }
    
}


extension TuBiaoZheXianYuanZhu_BadgeVC {
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if object is WKWebView {
            let modView = object as! WKWebView
            if modView === webView {
                if keyPath == TuBiaoZheXianYuanZhu_Status.progress {
                    updateProgress()
                } else if keyPath == TuBiaoZheXianYuanZhu_Status.title {
                    navigation.item.title = webView.title
                } else if keyPath == TuBiaoZheXianYuanZhu_Status.title {
                    navigation.item.title = webView.title
                }
            }
        }
    }
    
    private func updateProgress() {
        progressLabel.text = String(format: "第一次加载可能较慢，请耐心等候\n资源加载中(%.1f%%)", webView.estimatedProgress * 100)
        if webView.estimatedProgress > 0 && webView.estimatedProgress < 1 {
            self.progressView.isHidden = false
            self.progressLabel.isHidden = false
            self.progressView.setProgress(Float(webView.estimatedProgress), animated: true)
            if !self.indicatorView.isAnimating {
                self.indicatorView.startAnimating()
            }
        } else if webView.estimatedProgress == 1 {
            DispatchQueue.main.async { [weak self] in
                guard let self = self else {
                    return
                }
                self.loadWebSuccess = true
                self.indicatorView.stopAnimating()
                self.progressLabel.isHidden = true
                self.progressLabel.text = ""
                self.webView.isHidden = false
                self.progressView.isHidden = true
                self.progressView.setProgress(0, animated: true)
            }
        }
    }
}

extension TuBiaoZheXianYuanZhu_BadgeVC: WKUIDelegate {
    
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        return WKWebView()
    }
    
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        completionHandler("http")
    }
    
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        completionHandler(true)
    }
    
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        completionHandler()
    }
    
    func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
        webView.reload()
    }
}

extension TuBiaoZheXianYuanZhu_BadgeVC: WKNavigationDelegate {
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        decisionHandler(.allow)
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        decisionHandler(.allow)
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.indicatorView.stopAnimating()
    }
    
    // 加载失败
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: any Error) {
        self.indicatorView.stopAnimating()
        self.loadWebSuccess = false
    }
    
}

extension UIDevice {
    
    @objc public static func getAppDeviceModel() -> String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let deviceModel = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        return deviceModel
    }
    
    @objc public static func getAppDeviceOsVersion() -> String {
        let osVersion = UIDevice.current.systemVersion
        return osVersion
    }
    
}


extension UIViewController {
    func getNavigationBarHeight() -> CGFloat {
        return self.navigationController?.navigationBar.frame.size.height ?? 0
    }
    
    func getStatusBarHeight() -> CGFloat {
        return UIApplication.shared.statusBarFrame.size.height
    }
    
    func getNavTotalHeight() -> CGFloat {
        return getStatusBarHeight() + getNavigationBarHeight()
    }
}
